﻿using System.Collections.Generic;
using UnityEngine.Events;

public class TimeManager : ModuleBase<TimeManager>
{
    public List<FrameTimer> FrameTimers = new List<FrameTimer>();
    public List<ClockTimer> ClockTimers = new List<ClockTimer>();
    public List<object> RemoveQueue = new List<object>();

    public override void Init()
    {
        Framework.Instance.AddUpdate(this);
    }

    public override void Update(float dt)
    {
        RemoveTimer();

        for (int i = FrameTimers.Count - 1; i >= 0; i--)
        {
            if (FrameTimers[i].Trigger(dt))
                FrameTimers.RemoveAt(i);
        }

        for (int i = ClockTimers.Count - 1; i >= 0; i--)
        {
            if (ClockTimers[i].Trigger(dt))
                ClockTimers.RemoveAt(i);
        }
    }

    public void AddFrame(object target, UnityAction<float> func, int frames = 1, int count = 0)
    {
        FrameTimer frame = new FrameTimer()
        {
            Target = target,
            Func = func,
            Frames = frames,
            Count = count,
            IsLoop = count == 0,
            TriggerFrame = frames
        };
        FrameTimers.Add(frame);
    }

    public void AddClock(object target, UnityAction func, float during = 1, int count = 0)
    {
        ClockTimer clock = new ClockTimer()
        {
            Target = target,
            Func = func,
            During = during,
            Count = count,
            IsLoop = count == 0,
            TriggerTime = during
        };
        ClockTimers.Add(clock);
    }

    public void Remove(object target)
    {
        RemoveQueue.Add(target);
    }

    public void RemoveTimer()
    {
        if (RemoveQueue.Count > 0)
        {
            for (int i = 0, len = RemoveQueue.Count; i < len; i++)
            {
                object target = RemoveQueue[i];
                for (int j = FrameTimers.Count - 1; j >= 0; j--)
                {
                    if (FrameTimers[j].Target == target)
                        FrameTimers.RemoveAt(j);
                }

                for (int j = ClockTimers.Count - 1; j >= 0; j--)
                {
                    if (ClockTimers[j].Target == target)
                        ClockTimers.RemoveAt(j);
                }
            }
            RemoveQueue.Clear();
        }
    }
}

public class FrameTimer
{
    public object Target;
    public UnityAction<float> Func;
    public int Frames;
    public int Count;

    public bool IsLoop;
    public int TriggerFrame;

    public bool Trigger(float dt)
    {
        bool isDelete = false;
        if (--TriggerFrame <= 0)
        {
            TriggerFrame = Frames;
            Func(dt);
            if (!IsLoop && --Count <= 0)
                isDelete = true;
        }
        return isDelete;
    }
}

public class ClockTimer
{
    public object Target;
    public UnityAction Func;
    public float During;
    public int Count;

    public bool IsLoop;
    public float TriggerTime;

    public bool Trigger(float dt)
    {
        bool isDelete = false;
        TriggerTime -= dt;
        if (TriggerTime <= 0)
        {
            TriggerTime += During;
            Func();
            if (!IsLoop && --Count <= 0)
                isDelete = true;
        }
        return isDelete;
    }
}
